var util = require('util');
var fs = require('fs');
var async = require('async');
var mongodb = require('mongodb');
var ServerManager = require('../js/servers.js').ServerManager;
var jsName = 'merge_game_db.js';

function help() {
    console.log(util.format('node %s srcSid dstSid command', jsName));
    console.log(util.format('   command: plat|world'));
}

var argv = process.argv;
if (argv.length < 5) {
    help();
    process.exit(1);
}

/***************************************************
***************************************************/
var serverManager = new ServerManager();
var src = {sid: +argv[2]}; //需要合并的服务器ID
var dst = {sid: +argv[3]}; //需要合并的服务器ID
var cmd = argv[4];
var needSelectLevel = true; //是否选择最高等级角色作为默认角色

function log(content) {
    LOG(util.format('[%s %s] %j', jsName, cmd, content));
}

serverManager.load({slave:false, native:true}, function(err) {
    if (err) {
        log('load servers failed'); return;
    }

    start();
});

function start() {
    async.each([src, dst], function(server, cb) {
        var game = serverManager.gameServers[server.sid];
        if (!game|| !game.isValid()) {
            cb(util.format('server:%d invalid', server.sid)); return;
        }

        var db = serverManager.getGameServerDB(game);
        if (!db) {
            cb(util.format('server:%d db invalid', server.sid)); return;
        }
        
        server.game = game;
        server.db = db;
        cb();
    }, function(err) {
        if (err) {
            log(err); return;
        }

        switch (cmd) {
        case 'plat':
            mergePlat(); break;
        case 'world':
            mergeWorld(); break;
        default:
            log('unknown'); break;
        }
    });
}

function mergePlat() {
    var conflictPlats = [];
    var newPlat = [];

    [src, dst].forEach(function(server) {
        server.maxUID = 0;
        server.plats = {};
        server.conflictLevel = {};
        server.dbPlat = server.db.collection('plat');
        server.dbUser = server.db.collection('user');
    });

    async.series([function(cb) {
        async.each([src, dst], function(server, cb2) {
            log(util.format('server:%d plat loading ...', server.sid));

            var cursor = server.dbPlat.find();
            cursor.each(function(err3, item){
                if (err3) {
                    cb2(err3); return;
                }

                if (cursor.isClosed()) {
                    cb2(); return;
                }
                
                if (item) {
                    if (item.ai) {
                        server.maxUID = item.ai;
                    }
                    if (item.uid) {
                        server.plats[item._id] = item;
                    }
                }
            });
        }, function(err2) {
            cb(err2);
        });
    },

    function(cb) {
        log(util.format('src.maxUID:%d dst.maxUID:%d', src.maxUID, dst.maxUID));
        var srcPlats = src.plats;
        var dstPlats = dst.plats;
        for (var openid in srcPlats) {
            if (openid in dstPlats) {
                conflictPlats.push(openid);
            }
        }
        
        log(util.format('OpenID count src:%d dst:%d conflict:%d', 
            Object.keys(srcPlats).length, Object.keys(dstPlats).length, conflictPlats.length));        
        if (conflictPlats.length <= 0 || !needSelectLevel) {
            cb(); return;
        }

        async.each([src, dst], function(server, cb2) {
            log(util.format('server:%d conflict level loading ...', server.sid));

            var uids = [];
            conflictPlats.forEach(function(openID) {
                uids.push(server.plats[openID].uid); 
            });

            var cursor = server.dbUser.find({_id:{'$in':uids}}, {'status.level':1});
            cursor.each(function(err3, item){
                if (err3) {
                    cb2(err3); return;
                }

                if (cursor.isClosed()) {
                    cb2(); return;
                }
                
                if (item) {
                    server.conflictLevel[item._id] = item.status.level;
                }
            });

        }, function(err2) {
            cb(err2);
        });
    }, 
    
    function (cb) {
        newPlat.push({_id:'_userid', 'ai':Math.max(src.maxUID, dst.maxUID)});

        var srcPlats = src.plats;
        var dstPlats = dst.plats;
        var srcLevels = src.conflictLevel;
        var dstLevels = dst.conflictLevel;

        for (var openid in srcPlats) {
            if (openid in dstPlats) {
                var srcPlat = srcPlats[openid];
                var dstPlat = dstPlats[openid];
                
                if (!dstPlat.uids) {
                    dstPlat.uids = [dstPlat.uid];
                }

                if (srcPlat.uids) {
                    dstPlat.uids = dstPlat.uids.concat(srcPlat.uids);
                } else {
                    dstPlat.uids.push(srcPlat.uid);
                }
                
                if (needSelectLevel) {
                    var srcUserLevel = srcLevels[srcPlat.uid];
                    var dstUserLevel = dstLevels[dstPlat.uid];

                    if (srcUserLevel && (!dstUserLevel || srcUserLevel > dstUserLevel)) {
                        dstPlat.uid = srcPlat.uid; 
                    }
                }
            } else {
                newPlat.push(srcPlats[openid]);
            }
        }

        for (var openid in dstPlats) {
            newPlat.push(dstPlats[openid]);
        }
        log(util.format('new plat count:%d', Object.keys(newPlat).length));

        var platArrs = newPlat.split(10000);
        dst.dbPlat.remove({}, function(err2, doc) {
            if (err2) {
                cb(err2); return;
            }
            
            async.eachSeries(platArrs, function(plats, cb3) {
                dst.dbPlat.insert(plats, {'w':1}, function(err4, doc){
                    cb3(err4);
                });
            }, function(err3) {
                cb(err3);
            });
        });
    }], function(err, results) {
        if (err) {
            log(err);
            process.exit(-1);
        } else {
            log('done');
            process.exit(0);
        }
    });
}


function mergeWorld() {

    [src, dst].forEach(function(server) {
        server.leagues = {};
        server.leagueDuplicates = {};
        server.dbWorld = server.db.collection('world');
        server.dbUser = server.db.collection('user');
    });

    async.series([function(cb) {
        async.each([src, dst], function(server, serverCallback) {
            server.dbWorld.findOne({_id: 'league'}, {}, function(leagueError, leagueDoc) {
                if (leagueError || !leagueDoc) {
                    serverCallback(util.format("server:%d load league failed:%j", server.sid, leagueError)); return;
                }
                server.leagues = leagueDoc.league;

                server.dbWorld.findOne({_id:'league_duplicate'}, {}, function(duplicateError, duplicateDoc) {
                    if (duplicateError || !duplicateDoc) {
                        serverCallback(util.format("server:%d load leagueDuplicate failed", server.sid)); return;
                    }
                    server.leagueDuplicates = duplicateDoc;
                    serverCallback();
                });
            });
        }, function(err) {
            cb(err);
        });
    },
    
    function(cb) {
        var srcLeagues = src.leagues;
        var dstLeagues = dst.leagues;
        var srcLeagueDuplicates = src.leagueDuplicates;
        var dstLeagueDuplicates = dst.leagueDuplicates;
        var leagueConflicts = [];

        for (var leagueName in srcLeagues) {
            if (leagueName in dstLeagues) {
                leagueConflicts.push(leagueName); 
            }
        }
        log(util.format('league conflict:%d', leagueConflicts.length));

        var newLeague = {};
        var newLeagueDuplicate = {
            '_id': 'league_duplicate',
            'idgen': 0, 
            'leagues': {},
        };

        for (var leagueName in srcLeagues) {
            var league = srcLeagues[leagueName];
            if (leagueConflicts.indexOf(leagueName) >= 0) {
                leagueName = leagueName + 'S' + src.sid;
            }

            league.sid = src.sid;
            league.name = leagueName;
            newLeague[leagueName] = league;

            if (league.duplicate) {
                if (srcLeagueDuplicates && srcLeagueDuplicates.leagues[league.duplicate]) {
                    duplicate = srcLeagueDuplicates.leagues[league.duplicate];
                    var did = ++newLeagueDuplicate.idgen;
                    newLeagueDuplicate.leagues[did] = duplicate;
                    league.duplicate = did;
                } else {
                    league.duplicate = 0; 
                }
            }
        }

        for (var leagueName in dstLeagues)  {
            var league = dstLeagues[leagueName];
            if (leagueConflicts.indexOf(leagueName) >= 0) {
                leagueName = leagueName + '_S' + dst.sid;
            }

            league.sid = dst.sid;
            league.name = leagueName;
            newLeague[leagueName] = league;

            if (league.duplicate) {
                if (dstLeagueDuplicates && dstLeagueDuplicates.leagues[league.duplicate]) {
                    duplicate = dstLeagueDuplicates.leagues[league.duplicate];
                    var did = ++newLeagueDuplicate.idgen;
                    newLeagueDuplicate.leagues[did] = duplicate;
                    league.duplicate = did;
                } else {
                    league.duplicate = 0; 
                }
            }
        }

        dst.dbWorld.save({_id:'league','league':newLeague}, function(leagueError, leagueResult) {
            if (leagueError) {
                cb('save league failed'); return;
            }

            dst.dbWorld.save(newLeagueDuplicate, function(duplicateError, duplicateResult) {
                if (duplicateError) {
                    cb('save league duplicate failed'); return;
                }
                
                cb();
            });
        });
    }], function(err, results) {
        if (err) {
            log(err);
            process.exit(-1);
        } else {
            log('done');
            process.exit(0);
        }
    });
}

